# coding: utf-8
import logging
import json
import requests
from services.datamodel.student.models import (mm_Student)
from django.contrib.auth import authenticate
from django.http import JsonResponse, HttpResponseRedirect
from apps.baselogic.handlers.wechat_account import BaseHandler
from lib.wechat.message_template import mm_YiJiaoWechat
from lib.common import AbstractHandler, get_api_result
from project import settings
from project.settings import wx_settings, DOMAIN_URL
from project.settings_common import APPLET_CONFIG
from apps.student.handlers import (loginout)
from django.core.cache import cache


class WechatHandler(BaseHandler):
    def __init__(self):
        AbstractHandler.__init__(self, logging.getLogger("wechat"))
        self.METHOD_TAB = {
            'GET': {
                'auth_base': self.handle_wechat_auth,
                'test': self.handle_test,
                'start': self.handle_index,
                'config': self.handle_config_detail,
                'wechat_auth': self.handle_pay_auth,
                'wechat_pay_start': self.handle_pay_start,
                'wechat_pay_start_member': self.handle_pay_start_member,
                'wechat_auth_member': self.handle_pay_auth_member,

                'pay_event_start': self.handle_pay_event_start,
                'pay_event': self.handle_pay_event,

                'proxy_event_start': self.handle_proxy_event_start,
                'proxy_event': self.handle_proxy_event,
                'openid_start': self.handle_openid_start,
                'getopenid': self.handle_openid,
                'wecaht_app_login': self.wecaht_app_login,
            },
            'POST': {
                'connect': self.handle_connect,
                'wechat_login': self.handle_wechat_login,
                'add_auth_uv': self.handle_auth_uv,  # 用户授权页面uv
                'applet_auth': self.handle_applet_auth,  # 小程序获取openid
                'handle_applet_login': self.handle_applet_login,  # 小程序授权登录
                'mini_login': self.mini_login,
                'mini_authorization': self.mini_authorization
            }
        }

    def handle_wechat_auth(self, request, auth_type):
        code = request.GET['code']
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid')
        assert openid, (404, "微信端请求错误")
        # return JsonResponse(openid)
        data_model = self.AUTH_TYPE_DICT[auth_type]['data_model']
        data_obj = data_model.get_or_default(openid=openid)
        isbind = 1 if data_obj else 0
        return HttpResponseRedirect("".join((DOMAIN_URL, "/weekly/wechat/{}?nuclearcode={}&isbind={}")).format(
            auth_type, openid, isbind))

    def handle_index(self, request, auth_type):
        assert auth_type in self.AUTH_TYPE_LIST, (1, '错误的参数auth_type')
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}/api/" \
              "wechat/auth/{}/?action=auth_base&response_type=code&scope=snsapi_base#wechat_redirect".format(
            wx_settings.APP_ID, DOMAIN_URL, auth_type)
        return HttpResponseRedirect(url)

    def handle_pay_start(self, request):
        invitecode = request.GET.get('invitecode', '')
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}" \
              "&response_type=code&scope=snsapi_base&state={}#wechat_redirect".format(wx_settings.APP_ID, "{}/api/wechat/auth/?action=wechat_auth".format(DOMAIN_URL), invitecode)
        return HttpResponseRedirect(url)

    def handle_pay_start_member(self, request):
        content = request.GET.get('content', '')
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}" \
              "&response_type=code&scope=snsapi_base&state={}#wechat_redirect".format(wx_settings.APP_ID, "{}/api/wechat/auth/?action=wechat_auth_member".format(DOMAIN_URL),
                                                                                      content)
        return HttpResponseRedirect(url)

    def handle_pay_event_start(self, request):
        invtecode = request.GET.get('invitecode', '')
        one = request.GET.get('one', '')
        two = request.GET.get('two', '')
        classid = request.GET.get('classid', '')
        content = ",".join([invtecode, one, two, classid])
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}" \
              "&response_type=code&scope=snsapi_base&state={}#wechat_redirect".format(wx_settings.APP_ID, "{}/api/wechat/auth/?action=pay_event".format(DOMAIN_URL), content)
        return HttpResponseRedirect(url)

    def handle_pay_event(self, request):
        code = request.GET['code']
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid')
        assert openid, (404, "微信端请求错误")
        # return JsonResponse(openid)
        redirect_url = "".join((DOMAIN_URL, "/retail/extension?openid={}&invitecode={}&one={}&two={}&classid={}")).format(openid, *state.split(","))
        return HttpResponseRedirect(redirect_url)

    def handle_pay_auth_member(self, request):
        code = request.GET['code']
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid')
        assert openid, (404, "微信端请求错误")
        # return JsonResponse(openid)
        redirect_url = "".join((DOMAIN_URL, "/retail/payment?openid={}&content={}")).format(openid, state)
        return HttpResponseRedirect(redirect_url)

    def handle_pay_auth(self, request):
        code = request.GET['code']
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid')
        assert openid, (404, "微信端请求错误")
        # return JsonResponse(openid)
        redirect_url = "".join((DOMAIN_URL, "/retail/signUp?nuclearcode={}&invitecode={}")).format(openid, state)
        return HttpResponseRedirect(redirect_url)

    def handle_connect(self, request, auth_type):
        self.checkMandatoryParams(request, ['phone', 'password', 'openid'])
        self.is_int_params(request, ['phone', 'code'])
        phone = request.param_dict['phone']
        password = request.param_dict['password']
        # code = request.param_dict['code']
        openid = request.param_dict['openid']
        # check smscode
        # smsRet = sender.checkcode(BusinessCode.WECHATCONNECT, phone, code)
        # if smsRet['retcode']:
        #     return JsonResponse(smsRet)
        assert auth_type in self.AUTH_TYPE_LIST, (1, '错误的参数auth_type')
        user = authenticate(username=("".join((
            getattr(settings.USERNAME_TYPE_PREFIX, str.upper(auth_type)), phone))), password=password)
        # 如果老师的账号不是规范要求[2*#*_137777777]，则选择以前那种username格式
        if not user:
            user = authenticate(username=("".join(phone)), password=password)
        data_obj = getattr(user, auth_type)
        assert user and user.is_active and data_obj, (404, '该用户未注册或者请使用相应角色的手机登录.')
        data_obj.openid = openid
        data_obj.save(update_fields=['openid'])
        return JsonResponse({"retcode": 0})

    def handle_test(self, request):
        """
        测试发送消息
        """
        # from celery import group
        # from services.asyntask.notice_task import send_wechat_message
        # parent_wechat_push = group(send_wechat_message.subtask(*n) for n in [('otynd06vwxd7957a3E_DWc2NwtUQ', 2, 'teacher')]*10)
        # parent_wechat_push.apply_async()
        openid = request.param_dict.get('openid', 'otynd06vwxd7957a3E_DWc2NwtUQ')
        reportid = request.param_dict['reportid']
        utype = request.param_dict.get('type', 'teacher')
        mm_YiJiaoWechat.send_template_msg(openid, reportid, utype)
        return JsonResponse({"retcode": 0})

    def handle_config_detail(self, request):
        self.checkMandatoryParams(request, ['url'])
        url = request.param_dict['url']
        share_img = request.param_dict.get('share_img')
        surl = request.param_dict.get('surl')
        return JsonResponse(mm_YiJiaoWechat.getWechatConfig(url, share_img, surl))

    def handle_proxy_event_start(self, request):
        proxy_id = request.GET.get('proxy_id', '')
        exam_id = request.GET.get('exam_id', '')
        content = ",".join([proxy_id, exam_id])
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}" \
              "&response_type=code&scope=snsapi_base&state={}#wechat_redirect".format(wx_settings.APP_ID, "{}/api/wechat/auth/?action=proxy_event".format(DOMAIN_URL), content)
        return HttpResponseRedirect(url)

    def handle_proxy_event(self, request):
        code = request.GET['code']
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid')
        assert openid, (404, "微信端请求错误")
        # return JsonResponse(openid)
        redirect_url = "".join((DOMAIN_URL, "/retail/checkvideos/exam?pid={}&id={}&openid={}")).format(*state.split(","), openid)
        return HttpResponseRedirect(redirect_url)

    def handle_openid_start(self, request):
        redurl = request.GET.get('redurl', '')
        url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}" \
              "&response_type=code&scope=snsapi_base&state={}#wechat_redirect".format(
            wx_settings.APP_ID, "{}/api/wechat/auth/?action=openid_end".format(DOMAIN_URL), redurl)
        return HttpResponseRedirect(url)

    def handle_openid(self, request):
        self.checkMandatoryParams(request, ["code", "quiet"])
        self.is_int_params(request, ['quiet'])
        quiet = int(request.param_dict['quiet'])
        code = request.GET['code']
        state = request.GET.get('state')
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid', None)
        if not openid:
            self.app_logger.error(str(result))
            return JsonResponse({'retcode': 1, 'msg': "微信服务器错误!"})
        # return JsonResponse(openid)
        # redirect_url = "".join((DOMAIN_URL, "{}/?openid={}")).format(state, openid)
        if quiet:
            return JsonResponse({'retcode': 0, 'openid': openid})
        # 第二步 得到access token，openid，并 根据它们 获取用户信息
        access_token = result.get('access_token', None)
        getInfoUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN' % (
            access_token, openid)
        retObj = get_api_result(getInfoUrl)

        if 'nickname' not in retObj:
            return JsonResponse({'retcode': 1, 'msg': '获取用户信息失败'})
        retObj['retcode'] = 0

        return JsonResponse(retObj)

    def handle_wechat_login(self, request):
        self.checkMandatoryParams(request, ["weixin_code", "share_code", "channel"])
        evach = request.POST.get('evach', '')
        code = request.POST['weixin_code']
        share_code = request.POST['share_code']
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format(
            wx_settings.APP_ID, wx_settings.APP_SECRET, code)
        result = get_api_result(url_str)
        openid = result.get('openid', None)
        if result.get('errcode'):
            self.app_logger.error(str(result))
            return JsonResponse({'retcode': 1, 'msg': "微信服务器错误!"})
        access_token = result.get('access_token', None)
        getInfoUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN' % (
            access_token, openid)
        retObj = get_api_result(getInfoUrl)
        if retObj.get('errcode'):
            self.app_logger.error(str(retObj))
            return JsonResponse({'retcode': 1, 'msg': "微信服务器错误!"})
        # 查询用户
        # 将返回的数据塞入request
        sex = {1: 'male', 2: 'female', 3: 'unknown', 0: 'unknown'}
        request.POST._mutable = True
        # request.POST['gender'] = sex[retObj.get('sex')]
        # request.POST['provincename'] = retObj.get('provincename', '')
        request.POST['cityname'] = retObj.get('cityname', '')
        request.POST['nickname'] = retObj.get('nickname', '')
        request.POST['avatar'] = retObj.get('headimgurl', '')
        request.POST['openid'] = retObj.get('openid', '')
        request.POST['wechat_openid'] = retObj.get('openid', '')
        request.POST['ostype'] = "3"
        request.POST['evach'] = evach
        #request.POST['unionid'] = retObj.get('unionid', '')
        cache.set('user_unionid:'+str(retObj.get('openid', '')), retObj.get('unionid', ''), 3600)
        return loginout.handler.m_login(request)
        # return JsonResponse(res)

    def handle_auth_uv(self, request):
        from services.datamodel.delivery.models import mm_DynamicDelivery
        from django.db.models import F
        id = request.POST.get('id', 0)
        mm_DynamicDelivery.filter(id=id).update(auth_uv=F('auth_uv') + 1)
        return self.success()

    def handle_applet_auth(self, request):
        self.checkMandatoryParams(request, ['code'])
        code = request.POST.get('code')
        s_id = request.POST.get('student_id', 0)
        url = f'https://api.weixin.qq.com/sns/jscode2session?appid={APPLET_CONFIG.APPID}' \
              f'&secret={APPLET_CONFIG.SECRET}&js_code={code}&grant_type=authorization_code'
        try:
            result = json.loads(requests.get(url=url).text)
            if result.get('errcode', 0) != 0:
                self.app_logger.error(result)
                return self.error('授权失败')
            stu = mm_Student.get(id=s_id)
            if stu.applet_openid and stu.unionid:
                if stu.applet_openid == result.get('openid') and stu.unionid == result.get('unionid'):
                    return self.success()
                return self.error('授权失败，该手机用户已绑定微信公众号')
            if mm_Student.filter(applet_openid=result.get('openid'), unionid=result.get('unionid')).exists():
                self.app_logger.error(result)
                return self.error('授权失败，该微信小程序用户已绑定手机')
            stu.applet_openid = result.get('openid')
            stu.unionid = result.get('unionid')
            stu.save()
            return self.success()
        except Exception as e:
            logging.error(e)
            return self.error('授权失败')

    def handle_applet_login(self, request):
        """小程序登录获取session"""
        self.checkMandatoryParams(request, ['applet_code', "share_code", "channel", 'nickname', 'avatar'])
        code = request.POST.get('applet_code')
        url = f'https://api.weixin.qq.com/sns/jscode2session?appid={APPLET_CONFIG.APPID}' \
              f'&secret={APPLET_CONFIG.SECRET}&js_code={code}&grant_type=authorization_code'
        try:
            res = json.loads(requests.get(url=url).text)
            if res.get('errcode', 0) != 0:
                self.app_logger.error(res)
                return self.error('微信服务器内部错误')
            from django.core.cache import cache
            from apps.student.handlers import loginout
            # save session_key 2*86400
            session_key = res.get('session_key')
            openid = res.get('openid')
            cache.set(f'{openid}_session_key', session_key, 2*86400)
            # 将返回的数据塞入request
            request.POST._mutable = True
            mobile = request.POST.get('mobile')

            # 邀请人必须绑定手机号才可以锁粉
            share_code = request.POST.get('share_code')
            stu = mm_Student.filter(share_code=share_code).first()
            if stu and not stu.mobile:
                request.POST['share_code'] = ""

            # 通过小程序码注册进入，通过手机号查找分享码，channel=12:抽奖券小程序码，14:测评小程序码
            if mobile:
                request.POST['share_code'] = mm_Student.get(mobile=mobile).share_code
            request.POST['applet_openid'] = res.get('openid', '')
            request.POST['unionid'] = res.get('unionid', '')
            request.POST['ostype'] = "3"
            return loginout.handler.m_login(request)
        except Exception as e:
            self.app_logger.error(e)
            return self.error("登录失败")

    def wecaht_app_login(self, request):
        """
        微信app授权登入
        :param request:
        :return:
        """
        code = request.GET.get('code')
        state = request.GET.get('state')
        self.app_logger.error("code:{}, state: {}".format(code, state))
        url_str = "https://api.weixin.qq.com/sns/oauth2/access_token?" \
                  "appid={}&secret={}&code={}&grant_type=authorization_code".format('wx63f0de6869796f5b',
                                                                                    'b932e583e771347958604c765377d500',
                                                                                    code)
        try:
            result = get_api_result(url_str)
            access_token = result.get('access_token', None)
            openid = result.get('openid', None)
            getInfoUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN' % (
                access_token, openid)
            retObj = get_api_result(getInfoUrl)
            if retObj.get('errcode'):
                self.app_logger.error(str(retObj))
                return self.error("微信服务器错误")
            if not retObj.get('openid'):
                return self.error("微信服务器错误")
            request.POST._mutable = True
            request.POST['cityname'] = retObj.get('city', '')
            request.POST['nickname'] = retObj.get('nickname', '')
            request.POST['avatar'] = retObj.get('headimgurl', '')
            # request.POST['openid'] = retObj.get('openid', '')
            request.POST['is_app_wectch'] = 1
            request.POST['unionid'] = retObj.get('unionid', '')
            request.POST['ostype'] = "3"
            request.POST['wechat_openid'] = retObj.get('openid', '')
            cache.set('user_unionid_'+str(retObj.get('unionid', '')), retObj.get('unionid', ''), 3600*10)
            return loginout.handler.m_login(request)
        except Exception as e:
            self.app_logger.error(e)
            return self.error("登录失败")


    def mini_login(self, request):
        """
        优势小程序登入
        :param request:
        :return:
        """
        self.checkMandatoryParams(request, ['mini_code', "channel", 'o_id', 'u_id'])
        o_id = request.POST.get('o_id')
        u_id = request.POST.get('u_id')
        share_code = request.POST.get('share_code')
        code = request.POST.get('mini_code')
        channel = request.POST.get('channel')
        avatar = request.POST.get('avatar')
        nickname = request.POST.get('nickname')
        url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}".format(
            "wx3af648c742d8be80", "37829be2b13040fcc425b4dfd667092f"
        )
        retObj = get_api_result(url)
        if retObj.get('errcode'):
            self.app_logger.error(str(retObj))
            return self.error("微信服务器错误")
        access_token = retObj.get('access_token', None)
        phone_url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={}".format(access_token)
        res = json.loads(requests.post(url=phone_url, json={"code": code}).text)
        if res.get('errcode', 0) != 0:
            self.app_logger.error(res)
            return self.error('微信服务器内部错误')
        phone_info = res.get('phone_info')
        phoneNumber = phone_info['phoneNumber']
        purePhoneNumber = phone_info['purePhoneNumber']
        countryCode = phone_info['countryCode']
        request.POST._mutable = True
        request.POST['nickname'] = nickname
        request.POST['avatar'] = avatar
        request.POST['share_code'] = share_code
        request.POST['channel'] = channel
        request.POST['username'] = purePhoneNumber
        request.POST['ostype'] = "3"
        request.POST['mini'] = "phone"
        request.POST['o_id'] = o_id
        request.POST['un_id'] = u_id
        return loginout.handler.m_login(request)

    def mini_authorization(self, request):
        """
        小程序登录
        :param request:
        :return:
        """
        self.checkMandatoryParams(request, ['codes'])
        code = request.POST.get('codes')
        url = "https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code".format(
            "wx3af648c742d8be80", "37829be2b13040fcc425b4dfd667092f", code
        )
        retObj = get_api_result(url)
        if retObj.get('errcode'):
            self.app_logger.error(str(retObj))
            return self.error("微信服务器错误")
        session_key = retObj.get('session_key', None)
        unionid = retObj.get('unionid', None)
        openid = retObj.get('openid', None)
        user = mm_Student.get_or_default(zb_openid=openid)
        if user:
            request.POST._mutable = True
            request.POST['ostype'] = "3"
            request.POST['mini'] = "phone"
            request.POST['username'] = user.mobile
            request.POST['o_id'] = openid
            request.POST['un_id'] = unionid
            return loginout.handler.m_login(request)
        return self.success({"session_key": session_key, "unionid": unionid, "openid": openid, 'user': None})



handler = WechatHandler()
